/*-CREATE SERVER-*/
const express = require('express'),
    app = express(),
    bodyParser = require('body-parser'),
    fs = require('fs'),
    SparkMD5 = require('spark-md5'),
    PORT = 8888;
app.listen(PORT, () => {
    console.log(`THE WEB SERVICE IS CREATED SUCCESSFULLY AND IS LISTENING TO THE PORT：${PORT}`);
});
app.use(bodyParser.urlencoded({
    extended: false,
    limit: '1024mb'
}));

/*-API-*/
const multiparty = require("multiparty"),//这个模块用来处理form-data数据
    uploadDir = `${__dirname}/upload`;

function handleMultiparty(req, res, temp) {
    return new Promise((resolve, reject) => {
        // multiparty的配置
        let options = {
            maxFieldsSize: 200 * 1024 * 1024//这个配置表示你支持的文件最大上传多大
        };
        !temp ? options.uploadDir = uploadDir : null;//options.uploadDir表示你上传的地址是什么
        let form = new multiparty.Form(options);//把options对象放进去表示开始传文件了
        // multiparty解析
        form.parse(req, function (err, fields, files) {
            if (err) {
                res.send({
                    code: 1,
                    reason: err
                });
                reject(err);
                return;
            }
            resolve({
                fields,
                files
            });
        });
    });
}

// 基于FORM-DATA上传数据
app.post('/single1', async (req, res) => {
    console.log("req",req)
    let {
        files
    } = await handleMultiparty(req, res);//拿到的files是你上传的多个文件的信息,files.file[0]就是你上传的那个文件的信息对象
    let file = files.file[0];
    console.log('file.originalFilename→',file.originalFilename);
    console.log('file.path→',file.path);
    res.send({
        code: 200,
        originalFilename: file.originalFilename,//originalFilename表示你当初上传的原始文件名
        path: file.path.replace(__dirname, `http://127.0.0.1:${PORT}`)//返回去带服务器端口号和ip的文件地址
        //把file.path地址当中表示__dirname的替换成服务器地址
    });
});

// 上传BASE64
app.post('/single2', (req, res) => {
    let {
        chunk,
        filename
    } = req.body;

    // chunk的处理：转换为buffer解码
    chunk = decodeURIComponent(chunk);
    chunk = chunk.replace(/^data:image\/\w+;base64,/, "");//把base64开头去掉
    chunk = Buffer.from(chunk, 'base64');//把base64转换成刚Buffer数据

    // 存储文件到服务器
    let spark = new SparkMD5.ArrayBuffer(), //SparkMD5可以通过文件内容生成一个文件名的hash值
        suffix = /\.([0-9a-zA-Z]+)$/.exec(filename)[1],//这个接口是获得传进来的文件的后缀名
        path;
    spark.append(chunk);//然后把解析后的buffer数据放到Spark中
    // 通过spark.end()可以拿到文件解析后的hash文件名
    // 使用SparkMD5这个模块是根据文件内容生成文件名的hash值,而写入文件使用,fs.writeFileSync(path, chunk),时地址一样会覆盖的重新写入所以不会出现上传多次同一张图片/文件后端同时保存多张同一图片/文件
    path = `${uploadDir}/${spark.end()}.${suffix}`;//拿到写入文件夹的地址
    const dir=`${uploadDir}`
    const files=fs.readdirSync(dir)
    console.log("files→",files)
    var arr=[]
    files.forEach(function(item){
        if(item==`${spark.end()}.${suffix}`){
            arr.push(item)
        }
    })
    if(arr.length==0){
        fs.writeFileSync(path, chunk);//然后把文件写入到相应的文件夹
    }//如果文件夹内有同样的文件就不写入而是直接返回图片地址。
    res.send({
        code: 200,
        originalFilename: filename,
        path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
    });
});

// 切片上传 && 合并
app.post('/single3', async (req, res) => {
    let {
        fields,
        files
    } = await handleMultiparty(req, res, true);

    let [chunk] = files.chunk,
        [filename] = fields.filename;
    let hash = /([0-9a-zA-Z]+)_\d+/.exec(filename)[1],//因为我们传过来的每一个切片的filename都是hash_索引+文件格式, 左边代码作用是我们拿到前端传过来文件的hash名
        // suffix = /\.([0-9a-zA-Z]+)$/.exec(file.name)[1],//如左是拿到传过来文件的后缀名
        path = `${uploadDir}/${hash}`;//会临时创建一个文件夹,文件夹是以hash值命名的,后面传过来的同hash名的切片块都放在这个文件夹里
    !fs.existsSync(path) ? fs.mkdirSync(path) : null;
    // fs.existsSync(path)这个api是为了检测path这个文件目录是否存在的,如果存在就会检测到返回true否则返回false
    // fs.mkdirSync(path)创建文件夹
    path = `${path}/${filename}`;
    // 判断文件是否存在,如果存在的话那么就直接返回文件地址,实现秒传
    fs.access(path, async err => {
        // 存在的则不再进行任何的处理
        if (!err) {
            res.send({
                code: 200,
                path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
            });
            return;
        }

        // // 为了测试出效果，延迟1秒钟
        // await new Promise(resolve => {
        //     setTimeout(_ => {
        //         resolve();
        //     }, 200);
        // });

        // 不存在的再创建,写入对应带hash名的地址下
        let readStream = fs.createReadStream(chunk.path),
            writeStream = fs.createWriteStream(path);
        readStream.pipe(writeStream);
        readStream.on('end', function () {
            fs.unlinkSync(chunk.path);
            res.send({
                code: 200,
                path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
            });
        });
    });
});

app.get('/merge', (req, res) => {
    let {
        hash
    } = req.query;

    let path = `${uploadDir}/${hash}`,
        fileList = fs.readdirSync(path),
        suffix;
    fileList.sort((a, b) => {//把文件切片排序
        let reg = /_(\d+)/;
        return reg.exec(a)[1] - reg.exec(b)[1];
    }).forEach(item => {
        !suffix ? suffix = /\.([0-9a-zA-Z]+)$/.exec(item)[1] : null;
        fs.appendFileSync(`${uploadDir}/${hash}.${suffix}`, fs.readFileSync(`${path}/${item}`));
        fs.unlinkSync(`${path}/${item}`);
    });
    fs.rmdirSync(path);
    res.send({
        code: 200,
        path: `http://127.0.0.1:${PORT}/upload/${hash}.${suffix}`
    });
});

app.use(express.static('./'));
app.use((req, res) => {
    res.status(404);
    res.send('NOT FOUND!');
});